/*
@2024-02-06: add a 279ms delday after sending 'close' to the shutter.
@2024-02-05: 0204晚的观测又出现了多次出现完全一样的图了，经过对日志的分析，认为是OCS端开了多个，导致ICS“几乎”同时给SoC发送
             了3次指令，导致CCD驱动时序参数的备份受影响，之后的CCD只是刷新，并没有真正读出。现在将参数的备份移至
             MephistoCAM_Config MCAM_Config初始化后，仅且仅做一次备份，这样它们就不会再受影响了。
@2024-02-03: 增加向ICS发送快门“开”、“关”的时间戳
@2024-02-03: update time stamp output precision to microseconds

@2024-01-31: optimize exposure time precision control

@2024-01-31: add log output to tmp/log-xxxx_xx_xx.txt
*/

#include "MephistoCAM.h"

#define PORT            1001
#define LISTEN_QUEUE    16
#define BUFFER_SIZE     1024

time_t arm_sys_time = 0;
struct timeval start;
struct timeval end;

char timestamp0[26]; // 'op' + 23+'\n' = 26
char timestamp1[26]; // 'cl' + 23+'\n' = 26
char timestamp[51];

// double time_diff(struct timeval *start, struct timeval *end){
//     return (end->tv_sec - start->tv_sec) + 1e-6*(end->tv_usec - start->tv_usec);
// }

////////////////////////////////////////////////////////////////////////////////////
// 备份CCD驱动时序参数
// backup vtrans parameters
int vtrans_num_bak; //      = mcfg->config_ccd_drive->vtrans_num;
int imgCLK1_cnt_min_bak;    // = mcfg->config_ccd_drive->imgCLK1_cnt_min;
int imgCLK1_cnt_max_bak;    // = mcfg->config_ccd_drive->imgCLK1_cnt_max;
int imgCLK2_cnt_min_bak;    // = mcfg->config_ccd_drive->imgCLK2_cnt_min;
int imgCLK2_cnt_max_bak;    // = mcfg->config_ccd_drive->imgCLK2_cnt_max;
int imgCLK3_cnt_min_bak;    // = mcfg->config_ccd_drive->imgCLK3_cnt_min;
int imgCLK3_cnt_max_bak;    // = mcfg->config_ccd_drive->imgCLK3_cnt_max;
int imgCLK4_cnt_min_bak;    // = mcfg->config_ccd_drive->imgCLK4_cnt_min;
int imgCLK4_cnt_max_bak;    // = mcfg->config_ccd_drive->imgCLK4_cnt_max;
int imgCLKx_cnt_MAX_bak;    // = mcfg->config_ccd_drive->imgCLKx_cnt_MAX;
int vtrans_state_cnt_max_bak;   // = mcfg->config_ccd_drive->vtrans_state_cnt_max;

// backup htrans parameters
int htrans_num_bak; // = mcfg->config_ccd_drive->htrans_num;
///////////////////////////////////////////////////////////////////////////////////

uint32_t cStatus = 0;   // 记录当前的工作状态，有且仅有两种可能得状态：
                        // 0: 表示空闲，没有曝光或者读出
                        // 1: 表示接收到ICS的拍摄指令了，正在执行中

char log_file[1024];
FILE *fp_log_file;

SPI_CONFIG *spi_config_daisy;// = (SPI_CONFIG*)malloc(sizeof(SPI_CONFIG));

// 在ccd_exposure的基础上增加了中断的功能 added@2024-01-01
// 输入参数中增加MephistoCAM_Config *mcfg，进一步方便参数传递 added@20240427
int ccd_exposure_with_abort(double t_exp, 
                            uint32_t *gpio_reg_ctrl, 
                            uint32_t *gpio_reg_status, 
                            uint32_t *gpio_reg_pl_ps_ddr_cnt, 
                            uint32_t n_row,
                            uint32_t n_col,
                            int n_bytes,    // 2 for 16bits unsigned; 4 for 32bits float
                            int fast_read_opt,
                            int is_dark,
                            char *filename,
                            char *log_shutter_fname,
                            char *log_camera_fname,
                            MephistoCAM_Config *mcfg );


int main( int argc, char *argv[] ) {

    //=================================================
    //  导入所有配置参数
    //=================================================
    char config_dir[1024];      // 保存参数配置文件所在的目录(相对路径)

    FILE *fp_wkdir = fopen(".WKDIR", "r");
    fscanf(fp_wkdir, "%s", config_dir);
    fclose(fp_wkdir);

    MephistoCAM_Config MCAM_Config;
    init_MephistoCAM_Config( &MCAM_Config, config_dir );

    spi_config_daisy = (SPI_CONFIG*)malloc(sizeof(SPI_CONFIG));
    setup_SPI_by_device_name( spi_config_daisy, "daisy" );

    fp_log_file = fopen("debug_VOD.log", "a+");

    //=========================================================================
    // GPIO 
    // uint32_t *gpio_flt_ctrl;        // ADDR_Float_Point_CTRL
    // uint32_t *gpio_flt_data;        // ADDR_Float_Point_DATA
    // uint32_t *gpio_in;              // ADDR_GPIO_IN
    // uint32_t *gpio_pl_ps;           // ADDR_PL_PS_DDR_CNT
    // uint32_t *gpio_out;             // ADDR_GPIO_OUT
    // uint32_t *gpio_out2;            // ADDR_GPIO_OUT
    // uint32_t *gpio_spi_ps_ctrl;     // ADDR_GPIO_SPI_PS_CTRL
    // uint32_t *gpio_spi_ps_data;     // ADDR_GPIO_SPI_PS_DATA

    int fd_gpio = open("/dev/mem", O_RDWR | O_SYNC);

    uint32_t *gpio_flt_ctrl     = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd_gpio, ADDR_Float_Point_CTRL);
    uint32_t *gpio_flt_data     = gpio_flt_ctrl + 2;

    uint32_t *gpio_in           = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd_gpio, ADDR_GPIO_IN);
    uint32_t *gpio_pl_ps        = gpio_in + 2;

    uint32_t *gpio_out          = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd_gpio, ADDR_GPIO_OUT);
    uint32_t *gpio_out2         = gpio_out + 2;

    uint32_t *gpio_spi_ps_ctrl  = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd_gpio, ADDR_GPIO_SPI_PS_CTRL);
    uint32_t *gpio_spi_ps_data  = gpio_spi_ps_ctrl + 2;

    MCAM_Config.gpio_flt_ctrl   = gpio_flt_ctrl;
    MCAM_Config.gpio_flt_data   = gpio_flt_data;
    MCAM_Config.gpio_in         = gpio_in;
    MCAM_Config.gpio_pl_ps      = gpio_pl_ps;
    MCAM_Config.gpio_out        = gpio_out;
    MCAM_Config.gpio_out2       = gpio_out2;
    MCAM_Config.gpio_spi_ps_ctrl= gpio_spi_ps_ctrl;
    MCAM_Config.gpio_spi_ps_data= gpio_spi_ps_data;

    ccd_exposure_with_abort(0, 
                            MCAM_Config.gpio_out, 
                            MCAM_Config.gpio_in, 
                            MCAM_Config.gpio_pl_ps, 
                            MCAM_Config.n_row,
                            MCAM_Config.n_col,
                            MCAM_Config.n_bytes,
                            0,
                            0,
                            "debug_VOD.bin",
                            MCAM_Config.log_shutter_fname,
                            MCAM_Config.log_camera_fname,
                            &MCAM_Config );

    free(spi_config_daisy);

    fclose(fp_log_file);

    return 0;
}



// 原先在RedOut.c源文件中，但是因为需要使用全局变量的原因，转移到这边
// ccd_exposure在ccd_readout的基础上增加了对快门的控制，其余功能一致
int ccd_exposure_with_abort(double t_exp, 
                            uint32_t *gpio_reg_ctrl,            // gpio_out
                            uint32_t *gpio_reg_status,          // gpio_in
                            uint32_t *gpio_reg_pl_ps_ddr_cnt,   // gpio_pl_ps
                            uint32_t n_row,
                            uint32_t n_col,
                            int n_bytes,
                            int fast_read_opt,
                            int is_dark,
                            char *filename,
                            char *log_shutter_fname,
                            char *log_camera_fname,
                            MephistoCAM_Config *mcfg ){


#if defined(_ENABLE_VOD_ADJUST_)
    // restore VOD to 29V (added @20240427)
    printf("[VOD_DEBUG] restore VOD to 29V(e2v) / 25V(44s)\n");
    set_reg_update_option( mcfg->config_daisy, mcfg->gpio_out );
    restore_OD_bias_voltage( mcfg->gpio_out, 
                             mcfg->gpio_out2,
                             mcfg->gpio_in,
                             spi_config_daisy,
                             mcfg->config_daisy );
#endif

    fprintf(stdout, "[%s]--> CCD readout starts ...\n", __func__);
    write_log(fp_log_file, "CCD readout start ...");

    gettimeofday(&start, NULL);

    ccd_readout_fp( gpio_reg_ctrl, 
                    gpio_reg_status, 
                    gpio_reg_pl_ps_ddr_cnt,
                    n_row,
                    n_col,
                    n_bytes,
                    0,
                    filename,
                    fp_log_file );
    
    gettimeofday(&end, NULL);

    double t_diff = time_diff(&start,&end);
    fprintf(stdout, "[%s]--> CCD readout ends, total time: %12.6f seconds\n", __func__, t_diff);

    char log_msg[128];
    sprintf(log_msg, "CCD readout ends, total time used: %12.6f seconds\n", t_diff);
    write_log(fp_log_file, log_msg );

    fprintf(stdout, "******** fflush fp_log_file ********\n");
    fflush(fp_log_file);

#if defined(_ENABLE_VOD_ADJUST_)
    // lower VOD to 10V (added @20240427)
    printf("[VOD_DEBUG] lower VOD to %f\n",_VOD_MIN_);
    set_reg_update_option( mcfg->config_daisy, mcfg->gpio_out );
    lower_OD_bias_voltage( mcfg->gpio_out, 
                           mcfg->gpio_out2,
                           mcfg->gpio_in,
                           spi_config_daisy,
                           mcfg->config_daisy );
#endif

    return 0;
}




